// vPresent is an immersive presentation creation and display application.
// Copyright (C) 2007 by Infiscape Corporation
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

// Server application
#include <OpenSG/OSGGLUT.h>
#include <OpenSG/OSGConfig.h>
#include <OpenSG/OSGClusterServer.h>
#include <OpenSG/OSGGLUTWindow.h>
#include <OpenSG/OSGRenderAction.h>

#include <boost/program_options.hpp>
namespace po = boost::program_options;

OSG::GLUTWindowPtr   gWindow;
OSG::RenderAction*   gRenderAction;
OSG::ClusterServer*  gClustServer;

void display()
{
   try
   {
      gClustServer->render(gRenderAction);               // Render the scene
      OSG::Thread::getCurrentChangeList()->clearAll();   // Clear change list
   }
   catch(std::exception &e)
   {
      std::cerr << e.what() << std::endl;
      std::cout << "Exiting with exception...\n" << std::endl;
      exit(1);
   }

}

void reshape(int w, int h)
{
   gWindow->resize( w, h );
}


int main(int argc,char **argv)
{
   int winid(0);
   bool        go_fullscreen(false);
   std::string server_name;
   std::string connection_type;
   std::string address;
   unsigned    service_port(8437);      // OpenSG default
   std::string service_group;

   // ---- ARGUMENT PROCESSING --- //
   try
   {
      po::options_description prog_opts("Options");

      prog_opts.add_options()
         ("help", "produce help message")
         ("fullscreen,f", "Run in fullscreen mode")
         ("name,n", po::value<std::string>()->default_value(server_name),
                    "Our server name (if machine:port, then acts as address also).")
         ("address,a", po::value<std::string>()->default_value(address),
                     "Address to wait for connections on.")
         ("type,t", po::value<std::string>()->default_value("StreamSock"),
                     "Communication method to use (StreamSock or Multicast)")
         ("service-port", po::value<unsigned>()->default_value(service_port),
                     "Service port to use.")
         ("service-group", po::value<std::string>()->default_value(""),
                     "Service group to use.")
         ;

      po::variables_map vm;
      po::store(po::command_line_parser(argc, argv).
                options(prog_opts).run(), vm);
      po::notify(vm);

      if ( vm.count("help") > 0 )
      {
         std::cout << prog_opts << std::endl;
         return 1;
      }

      if (vm.count("name") > 0)
      {
         server_name = vm["name"].as<std::string>();
         std::cout << "Set server name: " << server_name << std::endl;
      }

      if(vm.count("address") > 0)
      {
         address = vm["address"].as<std::string>();
         std::cout << "Set address to: " << address << std::endl;
      }

      if(vm.count("type") > 0)
      {
         connection_type = vm["type"].as<std::string>();
         if(! ( (std::string("StreamSock") == connection_type) || (std::string("Multicast") == connection_type)))
         {
            std::cout << "Invalid connection type: " << connection_type << std::endl;
            connection_type = "StreamSock";
         }
         std::cout << "Connection type set to: " << connection_type << std::endl;
      }

      if(vm.count("service_port") > 0)
      {
         service_port = vm["service_port"].as<unsigned>();
         std::cout << "Set service port to: " << service_port << std::endl;
      }

      if(vm.count("service-group") > 0)
      {
         service_group = vm["service-group"].as<std::string>();
         std::cout << "Set service group to: " << service_group << std::endl;
      }


      if ( vm.count("fullscreen") > 0 )
      {
         std::cout << "Fullscreen mode selected" << std::endl;
         go_fullscreen = true;
      }
   }
   catch (std::exception& ex)
   {
      std::cout << ex.what() << std::endl;
      return -1;
   }


   try
   {
      // Setup glut with defaults
      glutInit(&argc, argv);
      glutInitDisplayMode( GLUT_RGB |GLUT_DEPTH | GLUT_DOUBLE);

      OSG::ChangeList::setReadWriteDefault();
      OSG::osgInit(argc, argv);

      winid = glutCreateWindow(server_name.c_str());
      if(go_fullscreen)
      { glutFullScreen(); }

      glutDisplayFunc(display);
      glutIdleFunc(display);
      glutReshapeFunc(reshape);
      glutSetCursor(GLUT_CURSOR_NONE);

      gRenderAction = OSG::RenderAction::create();

      gWindow = OSG::GLUTWindow::create();
      gWindow->setId(winid);
      gWindow->init();

      // Set OpenGL defaults that we expect
      //glDepthFunc( GL_LESS );
      //glEnable(GL_CULL_FACE);
      //glCullFace(GL_BACK);

      // Connect up as cluster server
      std::cout << "Accepting connections as cluster server named: " << server_name << std::endl;
      gClustServer = new OSG::ClusterServer(gWindow, server_name, connection_type, address, service_port, service_group);
      gClustServer->start();

      glutMainLoop();
   }
   catch(std::exception &e)
   {
      std::cerr << e.what() << std::endl;
      std::cout << "Exiting with exception...\n" << std::endl;
   }

   delete gClustServer;
   OSG::osgExit();

   return 0;
}

